using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Logging;
using System.Diagnostics;

namespace CoreManager.Core.Middleware
{
    /// <summary>
    /// 关联ID中间件 - 用于链路追踪
    /// </summary>
    public class CorrelationIdMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<CorrelationIdMiddleware> _logger;
        private const string CorrelationIdHeader = "X-Correlation-ID";
        private const string RequestIdHeader = "X-Request-ID";

        public CorrelationIdMiddleware(RequestDelegate next, ILogger<CorrelationIdMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 获取或生成关联ID
            var correlationId = GetOrGenerateCorrelationId(context);
            var requestId = GenerateRequestId();

            // 设置到HttpContext中供后续使用
            context.Items["CorrelationId"] = correlationId;
            context.Items["RequestId"] = requestId;

            // 设置到响应头中
            context.Response.Headers[CorrelationIdHeader] = correlationId;
            context.Response.Headers[RequestIdHeader] = requestId;

            // 设置到Activity中用于分布式追踪
            var activity = Activity.Current;
            if (activity != null)
            {
                activity.SetTag("correlation.id", correlationId);
                activity.SetTag("request.id", requestId);
                activity.SetTag("http.method", context.Request.Method);
                activity.SetTag("http.url", GetFullUrl(context.Request));
                activity.SetTag("user.id", GetUserId(context));
            }

            // 使用简化的日志范围 - 只保留关键追踪信息
            using (_logger.BeginScope(new Dictionary<string, object>
            {
                ["CorrelationId"] = correlationId,
                ["RequestId"] = requestId
            }))
            {
                await _next(context);
            }
        }

        /// <summary>
        /// 获取或生成关联ID
        /// </summary>
        private static string GetOrGenerateCorrelationId(HttpContext context)
        {
            // 从请求头获取关联ID
            var correlationId = context.Request.Headers[CorrelationIdHeader].FirstOrDefault();
            
            if (string.IsNullOrEmpty(correlationId))
            {
                // 如果没有关联ID，生成一个新的
                correlationId = GenerateCorrelationId();
            }

            return correlationId;
        }

        /// <summary>
        /// 生成关联ID
        /// </summary>
        private static string GenerateCorrelationId()
        {
            return $"COR-{DateTimeOffset.UtcNow:yyyyMMdd}-{Guid.NewGuid():N}"[..32];
        }

        /// <summary>
        /// 生成请求ID
        /// </summary>
        private static string GenerateRequestId()
        {
            return $"REQ-{DateTimeOffset.UtcNow:yyyyMMdd}-{Guid.NewGuid():N}"[..32];
        }

        /// <summary>
        /// 获取完整URL
        /// </summary>
        private static string GetFullUrl(HttpRequest request)
        {
            return $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}{request.QueryString}";
        }

        /// <summary>
        /// 获取用户ID
        /// </summary>
        private static string? GetUserId(HttpContext context)
        {
            return context.User?.FindFirst("sub")?.Value ??
                   context.User?.FindFirst("userId")?.Value ??
                   context.User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        }

        /// <summary>
        /// 获取客户端IP地址
        /// </summary>
        private static string GetClientIpAddress(HttpContext context)
        {
            var ipAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            }
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = context.Connection.RemoteIpAddress?.ToString();
            }

            return ipAddress ?? "Unknown";
        }
    }

    /// <summary>
    /// 关联ID中间件扩展
    /// </summary>
    public static class CorrelationIdMiddlewareExtensions
    {
        /// <summary>
        /// 使用关联ID中间件
        /// </summary>
        public static IApplicationBuilder UseCorrelationId(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<CorrelationIdMiddleware>();
        }
    }
}